package com.hqyj.javaSpringBoot.modules.common.controller;



import com.hqyj.javaSpringBoot.modules.common.entiy.ExceptionLog;
import com.hqyj.javaSpringBoot.modules.common.entiy.ResultEntity;
import com.hqyj.javaSpringBoot.modules.common.service.ExceptionLogService;
import com.hqyj.javaSpringBoot.util.IPUtil;
import com.hqyj.javaSpringBoot.util.StringUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.UnauthorizedException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;

import javax.servlet.http.HttpServletRequest;
import java.lang.annotation.Annotation;
import java.time.LocalDateTime;

/**
 * @ControllerAdvice + @ExceptionHandler
 * 主要处理 Controller 层的异常（一般情况下 Service 、Dao 并不捕获
 * 异常，全抛给 Controller 处理），根据不同的异常做出不同的动作，
 * 但不能处理不进 Controller 的异常；
 */
@ControllerAdvice
public class ExceptionHandlerController {

    private final static Logger LOGGER=
            LoggerFactory.getLogger(ExceptionHandlerController.class);

    @Autowired
    private ExceptionLogService exceptionLogService;

    /**
     * 权限不足的异常，ArithmeticException  --- 算术异常暂时取代权限，后面修改
     * 转127.0.0.1/common/403
     * UnauthorizedException
     */
    @ExceptionHandler(value = UnauthorizedException.class)
    public ModelAndView exceptionHandlerFor403(HttpServletRequest request,Exception ex){

        insertExceptionLog(request, ex);
        if (isInterface(request)) {
            return jsonResult(ResultEntity.ResultStatus.FAILED.code,
                    "Unauthorized error", "/common/403");
        } else {
            return pageResult("/common/403", HttpStatus.FORBIDDEN);
        }
    }

    /**
     * 除权限异常之外的异常，并且调用了控制层的异常，
     * 跳转127.0.0.1/common/500
     * @return
     */
    @ExceptionHandler(value =  Exception.class)
    @ResponseBody
    public ModelAndView exceptionHandlerFor500(HttpServletRequest request,Exception ex){
        ex.printStackTrace();
        insertExceptionLog(request,ex);

        insertExceptionLog(request, ex);
        if (isInterface(request)) {
            return jsonResult(ResultEntity.ResultStatus.FAILED.code,
                    "Unauthorized error", "/common/500");
        } else {
            return pageResult("/common/500", HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    /**判断是否为接口*/
    private boolean isInterface(HttpServletRequest request) {
        HandlerMethod handlerMethod = (HandlerMethod) request.getAttribute(
                "org.springframework.web.servlet.HandlerMapping.bestMatchingHandler");
        Annotation[] classAnnotations = handlerMethod.getBeanType().getAnnotationsByType(RestController.class);
        Annotation[] methodAnnotations = handlerMethod.getMethod().getAnnotationsByType(ResponseBody.class);
        return (classAnnotations.length > 0) || (methodAnnotations.length > 0);
    }

    // 返回页面
    private ModelAndView pageResult(String url, HttpStatus status) {
        // 重定向到错误页面控制器
        return new ModelAndView("redirect:" + url, status);
    }

    // 返回 Json 数据
    private ModelAndView jsonResult(int status, String message, Object data) {
        ModelAndView mv = new ModelAndView(new MappingJackson2JsonView());
        mv.addObject("status", status);
        mv.addObject("message", message);
        mv.addObject("data", data);
        return mv;
    }


    /**
     * 数据库添加异常类型
     */

    public void insertExceptionLog(HttpServletRequest request,Exception ex){
            ex.printStackTrace();
            LOGGER.debug("===========  Log insert into db  ============");

            ExceptionLog exceptionLog=new ExceptionLog();
            //设置ip，request.getRemoteAddr,获取的ip不完全，封装了一个IPUtil工具类
            exceptionLog.setIp(IPUtil.getIpAddr(request));
            //设置path
            exceptionLog.setPath(request.getServletPath());
            //获取方法 HandlerMethod可以认为是包装有method的一个包装
            HandlerMethod handlerMethod=(HandlerMethod)request.getAttribute(
                    "org.springframework.web.servlet.HandlerMapping.bestMatchingHandler");
            if (handlerMethod!=null){
                exceptionLog.setClassName(handlerMethod.getBeanType().getName());
                exceptionLog.setMethodName(handlerMethod.getMethod().getName());
            }
            exceptionLog.setExceptionType(ex.getClass().getSimpleName());
            //设置错误信息,trim()
            // 方法用于删除字符串的头尾空白符，空白符包括：空格、制表符 tab、换行符等其他空白符等。
            // StringUtil.splitString,截取长度
        exceptionLog.setExceptionMessage(StringUtils.isBlank(ex.getMessage()) ? "" :
                StringUtil.splitString(ex.getMessage().trim(), 200));
            //使用的不是Hibernate，,所以 @PrePersist不会起作用
        exceptionLog.setCreateDate(LocalDateTime.now());

        exceptionLogService.insertExceptionLog(exceptionLog);

    }

}
